/*
 * Copyright 2014-2026 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wzq.framework.mvc;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.WebUtils;

/**
 * @author <a href="mailto:yanghao@0easy.com">杨浩</a>
 */
public class UtilApiHandlerMethod {
	
	/** 根据名称提取数据, 如果只有一个值，那么返回一个，负责是数组 */
	static Object resolveName(MethodParameter param, NativeWebRequest webRequest) throws Exception {
		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		MultipartHttpServletRequest multipartRequest = WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
		Class<?> type = param.getParameterType();
		String name = param.getParameterName();
		
		if (MultipartFile.class.equals(type)) {
			assertIsMultipartRequest(servletRequest, multipartRequest);
			return multipartRequest.getFile(name);
		} 
		if (isMultipartFileCollection(param)) {
			assertIsMultipartRequest(servletRequest, multipartRequest);
			return multipartRequest.getFiles(name);
		}
		if (isMultipartFileArray(param)) {
			assertIsMultipartRequest(servletRequest, multipartRequest);
			List<MultipartFile> multipartFiles = multipartRequest.getFiles(name);
			return multipartFiles.toArray(new MultipartFile[multipartFiles.size()]);
		}
		
		if ("javax.servlet.http.Part".equals(type.getName())) {
			assertIsMultipartRequest(servletRequest);
			return servletRequest.getPart(name);
		}
		if (isPartCollection(param)) {
			assertIsMultipartRequest(servletRequest);
			return new ArrayList<Object>(servletRequest.getParts());
		}
		if (isPartArray(param)) {
			assertIsMultipartRequest(servletRequest);
			return servletRequest.getParts().toArray(new Part[servletRequest.getParts().size()]);
		}

		Object arg = null;
		if (multipartRequest != null) {
			List<MultipartFile> files = multipartRequest.getFiles(name);
			if (!files.isEmpty()) {
				arg = (files.size() == 1 ? files.get(0) : files);
			}
		}
		if (arg == null) {
			String[] paramValues = webRequest.getParameterValues(name);
			if (paramValues != null) {
				arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
			}
		}
		return arg;
	}
	
	private static void assertIsMultipartRequest(HttpServletRequest request) {
		String contentType = request.getContentType();
		if (contentType == null || !contentType.toLowerCase().startsWith("multipart/")) {
			throw new MultipartException("The current request is not a multipart request");
		}
	}
	
	private static void assertIsMultipartRequest(HttpServletRequest request, MultipartHttpServletRequest multipartRequest) {
		assertIsMultipartRequest(request);
		Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
	}
	
	private static boolean isMultipartFileCollection(MethodParameter parameter) {
		return MultipartFile.class.equals(getCollectionParameterType(parameter));
	}

	private static boolean isMultipartFileArray(MethodParameter parameter) {
		return MultipartFile.class.equals(parameter.getParameterType().getComponentType());
	}

	private static boolean isPartCollection(MethodParameter parameter) {
		Class<?> collectionType = getCollectionParameterType(parameter);
		return (collectionType != null && "javax.servlet.http.Part".equals(collectionType.getName()));
	}

	private static boolean isPartArray(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType().getComponentType();
		return (paramType != null && "javax.servlet.http.Part".equals(paramType.getName()));
	}

	private static Class<?> getCollectionParameterType(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType();
		if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
			Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
			if (valueType != null) return valueType;
		}
		return null;
	}
}

